module memoryAlloctor (
    input wire clk,
    input wire rst,
    input wire ram_pick,
    input wire write_en,
    input wire [9:0] write_size,
    input wire [5:0] write_priority,
    input wire [5:0] write_port,
    input wire data_en_in,
    input wire [31:0] data_in,
    input wire queue_update_en,
    input wire [7:0] is_first_tail,
    input wire [9:0] queue_tail_old,
    input wire [15:0] queue_tail_new,
    input wire dequeue_en,
    input wire [7:0] is_last_head,
    input wire [9:0] dequeue_head_old,
    input wire [15:0] enqueue_sucess,
    output reg enqueue_en,
    output reg [5:0] enqueue_port,
    output reg [5:0] enqueue_priority,
    output reg [9:0] enqueue_value,
    output reg dequeue_head_new_en,
    output reg [5:0] dequeue_head_new_port,
    output reg [5:0] dequeue_head_new_priority,
    output reg [15:0] dequeue_head_new_value,
    output reg manager_write_ready,                    //RAM写就绪标志
    output reg address_ready,                          //地址准备就绪标志
    output reg write_padding_out,                      //写填充使能                   
    output reg write_en_out,                           //写使能
    output reg [14:0] write_address_out,               //写地址
    output reg [31:0] write_data_out,                  //写内容
    output reg read_en_out,                            //读使能
    output reg [14:0] read_address_out,                //读地址
    output reg [9:0] read_size_out                     //读取的数据包长度
);
    //队列中元素组织指针
    reg [15:0] block_queue_next [0:511];
    //数据块对应的地址寄存器组
    reg [9:0] block_address [0:511];
    //数据块对应的下一块序号寄存器组
    reg [9:0] block_next [0:511];
    //数据包对应的目标端口寄存器组
    reg [5:0] target_port [0:511];
    //当前数据快是否为数据包最后一块的标记寄存器组
    reg block_is_last [0:511];
    //读写计数器
    reg [9:0] read_address_counter;
    reg [9:0] write_address_counter;
    //空闲块队列
    reg [9:0] available_list [0:511];
    //空闲链表指针
    reg [9:0] available_head, available_tail;
    //读状态机
    reg read_state;
    reg [9:0] read_block;
    reg [14:0] read_address;
    //璁需要暂存的寄存器
    reg [9:0] history_data_size;
    reg [5:0] history_data_priority;
    reg [5:0] history_data_port;
    reg [9:0] history_data_index;
    //写状态机
    reg [1:0] write_state;
    reg [9:0] now_write_size;
    reg [9:0] write_block;
    integer i = 0;

    always @(posedge clk) begin
        if (rst) begin
            read_state <= 1'b0;
            write_state <= 2'b00;
            read_address_counter <= 0;
            write_address_counter <= 0;
            //初始化块的地址
            for (i = 0; i < 512; i=i+1) begin
                available_list[i] <= i;          
                block_address[i] <= i*64;
            end
            
            available_head <= 0;
            available_tail <= 511;

            write_padding_out <= 0;
            address_ready <= 1'b0;

            enqueue_en <= 0;
            enqueue_port <= 0;
            enqueue_priority <= 0;
            enqueue_value <= 0;
        end
    end

    //初始化握手信号
    always @(posedge clk) begin
        if (write_state == 2'b01) begin
            manager_write_ready <= 1'b0;
        end
        
        if (write_state == 2'b00) begin
            manager_write_ready <= 1'b1;
        end
    end

    always @(posedge clk) begin
        //收到入队成功信号后，拉低自身的入队信号
        if (enqueue_en && enqueue_sucess[enqueue_port]) begin
            enqueue_en <= 0;
            enqueue_priority <= 0;
            enqueue_port <= 0;
        end
    end

    //读状态转换逻辑
    always @(posedge clk) begin
        if (write_state == 2'b00 && write_en && ram_pick) begin
            write_state <= 2'b01;
            address_ready <= 1'b1;
            //暂存信息，后面会用到
            history_data_size <= write_size;
            history_data_port <= write_port;
            history_data_priority <= write_priority;
            history_data_index <= available_list[available_head];
            //从空闲队列中取出一块分配给数据包使用
            write_block <= available_list[available_head];
            write_address_counter <= 0;

            //空闲队列指针向后移动并取模，实现循环队列的功能
            if (available_head + 1 < 512) begin
                available_head <= available_head + 1;
            end
            else begin
                available_head <= 0;
            end
        end
        else begin
            address_ready <= 1'b0;
        end
    end

    //数据已经就绪，可以考虑将数据写入到RAM
    always @(posedge clk) begin
        if (write_state == 2'b01 && data_en_in) begin
            write_state <= 2'b10;
            write_en_out <= 1'b1;
            write_data_out <= data_in;
            write_address_out <= block_address[write_block] + write_address_counter;
            write_address_counter <= write_address_counter + 1;
        end
    end

    always @(posedge clk) begin
        if (write_state == 2'b10) begin
            write_en_out <= 1'b1;
            write_data_out <= data_in;
            write_address_out <= block_address[write_block] + write_address_counter;
            write_address_counter <= write_address_counter + 1;
            if (write_address_counter >= history_data_size) begin
                write_padding_out <= 1'b1;
            end
            else begin
                write_padding_out <= 1'b0;
            end
            //如果已经写满了一个内存块
            if (write_address_counter == 64) begin
                if (write_block == history_data_index) begin
                    //如果是第一块写完了，发出入队请求
                    enqueue_en <= 1'b1;
                    enqueue_port <= history_data_port;
                    enqueue_priority <= history_data_priority;
                    enqueue_value <= history_data_index;
                end

                write_address_counter <= 1;
                if (history_data_size - 64 < history_data_size) begin //数据已经不足一个完整快
                    //记录一下next和last标记
                    block_is_last[write_block] <= 1'b0;
                    block_next[write_block] <= available_list[available_head];
                    write_block <= available_list[available_head];
                    if (available_head + 1 < 512) begin
                        available_head <= available_head + 1;
                    end
                    else begin
                        available_head <= 0;
                    end
                    //size减小
                    history_data_size <= history_data_size - 64;
                end
                else begin
                    //如果已经是最后一个块，记录一下last
                    block_is_last[write_block] <= 1'b1;
                    //拉低自身的写入信号
                    write_state <= 2'b00;
                    address_ready <= 1'b0;
                    write_en_out <= 1'b0;
                    write_padding_out <= 1'b0;
                end
            end
        end
    end

    assign manager_read_ready = ~read_state;

    //读逻辑
    always @(posedge clk) begin
        if (read_state == 1'b1 && read_address_counter < 64) begin
            read_en_out <= 1'b1;
            read_address_out <= block_address[read_block] + read_address_counter;
            read_address_counter <= read_address_counter + 1;
            //如果读到了一个块的最后一个字，则准备进行下一个块的读取
            if (read_address_counter == 63) begin
                read_address_counter <= 0;
                if (block_is_last[read_block]==1'b1) begin
                    //已经是最后一个块，不需要继续了
                    read_state <= 1'b0;
                end
                else if (block_is_last[read_block]==1'b0) begin
                    //根据next数组读取下一个块的内容
                    read_block <= block_next[read_block];
                    //计数器归零
                    read_address_counter <= 0;
                end
                //读取数据结束以后，将读取完毕的块号加入到空闲队列中
                available_list[available_tail] <= read_block;

                //空闲队列指针向后移动并取模，实现循环队列的功能
                if (available_tail + 1 < 512) begin
                    available_tail <= available_tail + 1;
                end
                else begin
                    available_tail <= 0;
                end
            end
        end
        else begin
            read_en_out <= 1'b0;
        end
    end

    //数据入队
    always @(posedge clk) begin
        if (queue_update_en) begin
            block_queue_next[queue_tail_old] <= queue_tail_new;
        end
    end

    //读状态转移
    always @(posedge clk) begin
        if (dequeue_en && read_state == 1'b0) begin
            //向外输出新的队头元素
            dequeue_head_new_value <= block_queue_next[dequeue_head_old];
            //修改当前读状态
            read_state <= 1'b1;
            read_block <= dequeue_head_old;
            read_address_counter <= 0;
        end
    end


endmodule